package cn.dinkevin.xui.camera;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaRecorder;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceView;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import cn.dinkevin.xui.util.FileUtil;
import cn.dinkevin.xui.util.LogUtil;
import cn.dinkevin.xui.widget.surface.VideoSurfaceView;

/**
 * 相机管理
 * Created by ChengPengFei on 2017/1/4 0004.
 */

public final class CameraManager {

    private CameraManager() {
    }

    private static CameraManager g_singleton = new CameraManager();

    public static CameraManager getInstance() {
        return g_singleton;
    }

    /**
     * 相机对象
     */
    private Camera g_camera;
    private boolean isBackCamera;
    private int cameraId;

    private final int PERMISSION_REQUEST_CODE = 17;
    public static final int PERMISSION_CAMERA_CODE = 16;

    // 权限获取
    private boolean permissionCamera = false;
    private boolean permissionWriteExternalStorage = false;
    private boolean permissionRecordAudio = false;

    /**
     * 高版本视频录制需要权限检测
     *
     * @param activity 当前 Activity
     *
     * @return true -> 已经获得录制视频、相机预览需要的权限；否则未获得
     */
    public boolean highVersionVideoRecordPermissionCheck(Activity activity) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
            highVersionCheckCameraPermissionCheck(activity);
            highVersionCheckWriteExternalStoragePermissionCheck(activity);
            highVersionRecordAudioPermissionCheck(activity);
            return permissionCamera && permissionWriteExternalStorage && permissionRecordAudio;
        } else {
            return true;
        }
    }

    /**
     * 高版本系统检测相机权限
     *
     * @param activity
     *
     * @return true -> 相机权限已获取
     */
    private boolean highVersionCheckCameraPermissionCheck(Activity activity) {
        permissionCamera = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
        return permissionCamera;
    }

    /**
     * 高版本y文件写入权限检测
     *
     * @param activity 当前 Activity
     *
     * @return true -> 已经获得文件写入权限；否则未获得
     */
    private boolean highVersionCheckWriteExternalStoragePermissionCheck(Activity activity) {
        permissionWriteExternalStorage = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
        return permissionWriteExternalStorage;
    }

    /**
     * 高版本录音权限权限检测
     *
     * @param activity 当前 Activity
     *
     * @return true -> 已经获得录制视频、相机预览需要的权限；否则未获得
     */
    private boolean highVersionRecordAudioPermissionCheck(Activity activity) {
        permissionRecordAudio = ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
        return permissionRecordAudio;
    }

    /**
     * 拍摄视频请求的权限
     *
     * @param activity
     */
    public void requestCameraPermissions(Activity activity) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
            List<String> permissions = new ArrayList<String>();
            if (!permissionRecordAudio) {//如果没有录音权限
                permissions.add(Manifest.permission.RECORD_AUDIO);
            }
            if (!permissionWriteExternalStorage) {//如果没有写存储的权限
                permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            }
            if (!permissionCamera) {//如果没有相机权限
                permissions.add(Manifest.permission.CAMERA);
            }
            activity.requestPermissions(permissions.toArray(new String[permissions.size()]), PERMISSION_CAMERA_CODE);
        }
    }

    /**
     * 高版本权限检测
     *
     * @param context      上下文
     * @param requestCode  请求码
     * @param permissions  已经获取的权限
     * @param grantResults 请求结果
     *
     * @return true -> 可以打开相机了；否则表示
     */
    public boolean onRequestPermissionsResult(Context context, int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == PERMISSION_REQUEST_CODE) {
            if (permissions == null)
                return false;
            for (int i = 0; i < permissions.length; i++) {
                String permission = permissions[i];
                if (permission.equals(Manifest.permission.CAMERA) && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                    permissionCamera = true;
                }

                if (permission.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE) && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                    permissionWriteExternalStorage = true;
                }

                if (permission.equals(Manifest.permission.RECORD_AUDIO) && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                    permissionRecordAudio = true;
                }
            }

            if (permissionCamera && permissionWriteExternalStorage && permissionRecordAudio) {
                openBackCamera(context);
                return true;
            }
        }
        return false;
    }

    /**
     * 打开前置相机
     *
     * @param context
     *
     * @return true -> 打开前置相机成功；否则失败
     */
    public boolean openFrontCamera(Context context) {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        int cameraCount = Camera.getNumberOfCameras();
        for (int i = 0; i < cameraCount; i++) {
            Camera.getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                try {
                    openCamera(context, i);
                    cameraId =i;
                    isBackCamera = false;
                } catch (Exception e) {
                    return false;
                }
                return true;
            }
        }
        return false;
    }

    /**
     * 打开后置相机
     *
     * @param context
     *
     * @return true -> 打开后置相机成功；否则失败
     */
    public boolean openBackCamera(Context context) {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        int cameraCount = Camera.getNumberOfCameras();
        for (int i = 0; i < cameraCount; i++) {
            Camera.getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                isBackCamera = true;
                cameraId =i;
                try {
                    openCamera(context, i);
                } catch (Exception e) {
                    return false;
                }
                return true;
            }
        }
        return false;
    }

    private Context context;

    /**
     * 打开相机
     *
     * @param context
     * @param cameraId 相机Id
     */
    private void openCamera(Context context, int cameraId) {

        this.context = context;

        if (g_camera != null) {
            g_camera.stopPreview();
            g_camera.release();
            g_camera = null;
        }

        if (mediaRecorder != null) {
            mediaRecorder.stop();
            mediaRecorder.release();
            mediaRecorder = null;
        }

        g_camera = Camera.open(cameraId);
        Camera.Parameters parameters = g_camera.getParameters();
        parameters.setFlashMode("off");                 // 无闪光灯
        parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
        parameters.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
        parameters.setPreviewFormat(ImageFormat.YV12);

        // 自动对焦
        List<String> focusModes = parameters.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        }

        //这两个属性 如果这两个属性设置的和真实手机的不一样时，就会报错
        g_camera.setParameters(parameters);

        // 横竖屏镜头自动调整
        if (context.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
            Activity activity= (Activity) context;
            parameters.set("orientation", "portrait"); //
            parameters.set("rotation", setCameraDisplayOrientation(activity,cameraId)); // 镜头角度转90度（默认摄像头是横拍）
            g_camera.setDisplayOrientation(setCameraDisplayOrientation(activity,cameraId)); // 在2.2以上可以使用
        } else // 如果是横屏
        {
            parameters.set("orientation", "landscape"); //
            g_camera.setDisplayOrientation(0); // 在2.2以上可以使用
        }
    }

    /**
     * 获取相机对象
     *
     * @return 相机对象
     */
    public Camera getCamera() {
        return g_camera;
    }

    // 限制视频显示的尺寸
    public static final int VIDEO_WIDTH_MAX = 1920;

    /**
     * 获取适合的预览尺寸
     */
    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizeList, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1d;
        double targetRatio = (double) w / h;
        if (sizeList == null) return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        for (Camera.Size size : sizeList) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            int diff = Math.abs(size.height - h);
            if (diff < minDiff) {
                optimalSize = size;
                minDiff = diff;
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizeList) {
                int diff = Math.abs(size.height - h);
                if (diff < minDiff) {
                    optimalSize = size;
                    minDiff = diff;
                }
            }
        }

        // 针对 2K机型或者特殊机型（例如：三星Galaxy S6） 视频录制的高端机型判断
        if(optimalSize.height > 1080 || optimalSize.width == optimalSize.height){
            optimalSize.width = 640;
            optimalSize.height = 480;
        }

        LogUtil.d("optional camera size height-width:",optimalSize.height,optimalSize.width);
        return optimalSize;
    }

    /**
     * 开启相机预览
     *
     * @param surfaceView 待显示预览画面的控件
     *
     * @return true -> 开启预览成功；否则失败
     */
    public boolean startPreview(SurfaceView surfaceView) {

        // 如果没有开启相机则打开相机
        if (null == g_camera && surfaceView==null) {
            LogUtil.e("camera is null");
            return false;
        }

        // 处理预览变形
        Camera.Parameters parameters = g_camera.getParameters();
        List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();
        Camera.Size size = getOptimalPreviewSize(sizeList, surfaceView.getWidth(), surfaceView.getHeight());
        if (size != null) {
            if (surfaceView instanceof VideoSurfaceView) {
                int surfaceWith = surfaceView.getWidth();
                int surfaceHeight = surfaceView.getHeight();
                if (size.height / (float) size.width > surfaceWith / (float) surfaceHeight) {
                    ((VideoSurfaceView) surfaceView).setSize(surfaceHeight * size.height / size.width, surfaceHeight);
                } else if (size.height / (float) size.width < surfaceWith / (float) surfaceHeight) {
                    ((VideoSurfaceView) surfaceView).setSize(surfaceWith, size.width * surfaceWith / size.height);
                }
            }
        }

        // 设置相机预览显示 View
        try {
            g_camera.setPreviewDisplay(surfaceView.getHolder());
            // 开启相机预览
            g_camera.startPreview();
        } catch (IOException e) {
            LogUtil.e("set camera preview", Log.getStackTraceString(e));
            return false;
        }
        return true;
    }

    /**
     * 停止相机预览
     */
    public void stopPreview() {
        if (null == g_camera)
            return;

        g_camera.stopPreview();
        g_camera.setPreviewCallback(null);
        try {
            g_camera.setPreviewDisplay(null);
        } catch (IOException e) {

        }
        g_camera.release();
        g_camera = null;
    }

    private AudioManager audioManager;
    private int alarmVolume, DTMVolume, notificationVolume, ringVolume;

    /**
     * 开启静音
     */
    private void disableSound() {
        if (null == audioManager) {
            audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        }

        // saveImage volume
        alarmVolume = audioManager.getStreamVolume(AudioManager.STREAM_ALARM);
        DTMVolume = audioManager.getStreamVolume(AudioManager.STREAM_DTMF);
        notificationVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);

        // set mute
        audioManager.setStreamMute(AudioManager.STREAM_SYSTEM, true);
        audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
        audioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0);
        audioManager.setStreamVolume(AudioManager.STREAM_DTMF, 0, 0);
        audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, 0, 0);
        audioManager.setStreamVolume(AudioManager.STREAM_RING, 0, 0);
    }

    /**
     * 关闭静音
     */
    private void enableSound() {
        audioManager.setStreamMute(AudioManager.STREAM_SYSTEM, false);
        audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false);
        audioManager.setStreamVolume(AudioManager.STREAM_DTMF, DTMVolume, 0);
        audioManager.setStreamVolume(AudioManager.STREAM_ALARM, alarmVolume, 0);
        audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, notificationVolume, 0);
        audioManager.setStreamVolume(AudioManager.STREAM_RING, ringVolume, 0);
    }

    private MediaRecorder mediaRecorder;
    private String videoRecordPath;

    /**
     * 开启视频录制
     *
     * @param targetPath 视频存储路径
     *
     * @return true -> 开启视频录制成功；否则失败
     */
    public boolean startVideoRecord(String targetPath, SurfaceView surfaceView,Activity activity) {
        if (g_camera == null)
            return false;

        int setFixPictureWidth = 320;       // 最小宽
        int setFixPictureHeight = 240;      // 最小高
        try {

            // 计算最合适的录制尺寸
            Camera.Parameters parameters = g_camera.getParameters();
            if(null != parameters){
                List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();
                Camera.Size size = getOptimalPreviewSize(sizeList, surfaceView.getWidth(), surfaceView.getHeight());

                if(setFixPictureHeight < size.height && setFixPictureWidth < size.width){
                    setFixPictureHeight = size.height;
                    setFixPictureWidth = size.width;
                }
            }

            g_camera.lock();
            g_camera.unlock();

            if (mediaRecorder != null) {
                mediaRecorder.stop();
                mediaRecorder.release();
                mediaRecorder = null;
            }

            mediaRecorder = new MediaRecorder();// 创建 MediaRecorder对象
            if (g_camera != null) {
                mediaRecorder.setCamera(g_camera);
            }

            // 设置录制视频源为Camera(相机)
            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
            // 设置录制完成后视频的封装格式THREE_GPP为3gp.MPEG_4为mp4
            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            // 设置录制的视频编码h263 h264
            mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            // 设置视频录制的分辨率。必须放在设置编码和格式的后面，否则报错
            mediaRecorder.setVideoSize(setFixPictureWidth, setFixPictureHeight);

            // 调整清晰度
            int pictureSize = setFixPictureWidth * setFixPictureHeight;
            int videoEncodingBitRate;
            if(pictureSize <= 300000){
                videoEncodingBitRate = 5;
            }else if(pictureSize <= 500000){
                videoEncodingBitRate = 4;
            }else{
                videoEncodingBitRate = 3;
            }
            mediaRecorder.setVideoEncodingBitRate(videoEncodingBitRate * 1024 * 1024);

            // 竖屏幕情况下
            if (isBackCamera) {
                // 如果是后置摄像头：
                mediaRecorder.setOrientationHint(setCameraDisplayOrientation(activity, cameraId));
//                mediaRecorder.setOrientationHint(90);
            } else {
                // 如果是前置摄像头
                mediaRecorder.setOrientationHint(270);
            }

            // 横屏幕情况下：
            // 如果是前置摄像头：
            // mediaRecorder.setOrientationHint(180);
            // 如果是后置摄像头：
            // mediaRecorder.setOrientationHint(0);
            // mediaRecorder.setPreviewDisplay(view_video.getHolder().getSurface());
            // 设置视频文件输出的路径
            FileUtil.create(targetPath);
            mediaRecorder.setOutputFile(targetPath);

            // 准备录制
            mediaRecorder.prepare();
            // 开始录制
            mediaRecorder.start();
        } catch (Exception e) {
            e.printStackTrace();
            LogUtil.e("start video record", Log.getStackTraceString(e));
            return false;
        }
        videoRecordPath = targetPath;
        return true;
    }

    /**
     * 停止视频录制
     *
     * @return 视频存储路径
     */
    public String stopVideoRecord() {

        if (mediaRecorder != null) {
            mediaRecorder.setOnErrorListener(null);
            mediaRecorder.setOnInfoListener(null);
            mediaRecorder.setPreviewDisplay(null);
            try {
                mediaRecorder.stop();
            } catch (Exception e) {
                LogUtil.e("release video record", e.getCause());
            }
            mediaRecorder.release();
            mediaRecorder = null;
        }

        stopPreview();

        return videoRecordPath;
    }

    public int setCameraDisplayOrientation(Activity activity,
                                                   int cameraId) {
        android.hardware.Camera.CameraInfo info =
                new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay()
                .getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0: degrees = 0; break;
            case Surface.ROTATION_90: degrees = 90; break;
            case Surface.ROTATION_180: degrees = 180; break;
            case Surface.ROTATION_270: degrees = 270; break;
        }

        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        return result;
    }
}
